package com.hcc.flow.server.advice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import com.alibaba.fastjson.JSONObject;
import com.hcc.flow.server.common.advice.RRException;
import com.hcc.flow.server.common.utils.BadWordUtil2;
import com.hcc.flow.server.config.EncryptProperties;

import net.sf.json.util.JSONUtils;

/**
 * 请求数据接收处理类<br>
 * 
 * 对加了的方法的数据进行解密操作<br>
 * 
 * 只对@RequestBody参数有效
 * 
 * @author yinjihuan
 * 
 * @about http://cxytiandi.com/about
 *
 */
@ControllerAdvice
public class EncryptRequestBodyAdvice implements RequestBodyAdvice {

	private Logger logger = LoggerFactory.getLogger(EncryptRequestBodyAdvice.class);

	@Autowired
	private EncryptProperties encryptProperties;

	@Override
	public boolean supports(MethodParameter methodParameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) {
		return true;
	}

	@Override
	public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
			Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}

	@Override
	public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
		if (!encryptProperties.isDebug()) {
			try {
				return new DecryptHttpInputMessage(inputMessage, encryptProperties.getKey(),
						encryptProperties.getCharset());
			} catch (RRException e) {
				logger.error(e.getMessage());
				throw new RRException(e.getMessage());
			} catch (Exception e) {
				logger.error("数据解密失败", e.getMessage());
				throw new RRException("数据解密失败:"+e.getMessage());
			}
		}
		return inputMessage;
	}

	@Override
	public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}
}

class DecryptHttpInputMessage implements HttpInputMessage {
	private Logger logger = LoggerFactory.getLogger(EncryptRequestBodyAdvice.class);
	private HttpHeaders headers;
	private InputStream body;

	public DecryptHttpInputMessage(HttpInputMessage inputMessage, String key, String charset) throws Exception {
		this.headers = inputMessage.getHeaders();
		String decryptBody = IOUtils.toString(inputMessage.getBody(), charset);

		logger.debug("传入的数据：" + decryptBody);
		//敏感词监测
		if(!decryptBody.contains("\"offset\"") && !decryptBody.contains("\"limit\"")){
			Set<String> set;
			if(decryptBody.contains("\"modelContent\"") && JSONUtils.mayBeJSON(decryptBody)){
				JSONObject jo = JSONObject.parseObject(decryptBody);
				jo.remove("modelContent");
				set = BadWordUtil2.getBadWord(jo.toJSONString(), 2);
			}else{
				set = BadWordUtil2.getBadWord(decryptBody, 2);
			}
			if(set.size() > 0){
				throw new RRException("操作失败!检测到数据中包含敏感词:" + set);
			}
		}
		this.body = IOUtils.toInputStream(decryptBody, charset);
	}

	@Override
	public InputStream getBody() throws IOException {
		return body;
	}

	@Override
	public HttpHeaders getHeaders() {
		return headers;
	}
}
